﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Text;
using System;
using System.Globalization;

public class GitHelper
{
    private static string GIT_PATH = "";

    private static string GitExePath
    {
        get
        {
            if (GIT_PATH == "")
            {
#if UNITY_EDITOR_WIN
                string[] strs = {"C","D","E","F"};
                foreach (var s in strs)
                {
                    string filePath = string.Format(@"{0}:\Program Files\Git\bin\git.exe", s);
                    if (File.Exists(filePath))
                    {
                        GIT_PATH = filePath;
                        break;
                    }
                }
                
#elif UNITY_EDITOR_OSX
                GIT_PATH = "/usr/bin/git";
#endif
            }
            return GIT_PATH;
        }
    }

    //[MenuItem("Assets/GitHelper/Test")]
    //public static void Test()
    //{ 
    //    var selectObj = Selection.activeObject;
    //    var path = AssetDatabase.GetAssetPath(selectObj);
    //    CheckInTimeUpdate(path, new DateTime(2019, 8, 12), new DateTime(2019, 8, 12));
    //}

    public static int UpdateTimeLimit = -1;

    //[MenuItem("Assets/GitHelper/打印提交记录（选中文件）")]
    //public static void LogRecentCommits()
    //{
    //    var selectObj = Selection.activeObject;
    //    if (selectObj == null)
    //    {
    //        Debug.LogError("请先选中文件");
    //        return;
    //    }

    //    string recentCommit = GetRecentCommitLog(selectObj);
    //    Debug.Log(recentCommit);
    //}


    //public static void LogIsNewUpdate()
    //{
    //    var selectObj = Selection.activeObject;
    //    if (selectObj == null)
    //    {
    //        Debug.LogError("请先选中文件");
    //        return;
    //    }

    //    bool isUpdate = CheckIsRecentUpdate(selectObj);
    //    Debug.Log("是否一个月内有更改 ： " + isUpdate);
    //}

    public static string GetRecentCommitLog(string filePath)
    {
        if (GitExePath == "") return "";
        FileInfo fileInfo = new FileInfo(filePath);
        string log, err;
        ExecuteGitCommand(string.Format("log --pretty=format:\"%an : %ai\" {0}", fileInfo.Name), fileInfo.DirectoryName, out log, out err);
        return log;
    }


    public static string GetCurBranchName()
    {
        string log, err;
        ExecuteGitCommand("rev-parse --abbrev-ref HEAD", Directory.GetCurrentDirectory(), out log, out err, 1);
        if (string.IsNullOrEmpty(err) && !string.IsNullOrEmpty(log))
        {
            return log.Replace("\n", "");
        }
        return null;
    }

    /// <summary>
    /// 是否一个月内处理过文件 
    /// </summary>
    /// <returns></returns>
    //public static bool CheckIsRecentUpdate(Object obj, float time = 2678400)
    //{
    //    if (GitExePath == "") return false;
    //    var path = AssetDatabase.GetAssetPath(obj);
    //    return CheckIsRecentUpdate(path, time);
    //}

    private static Dictionary<float, Dictionary<string, bool>> DirUpdateTimeCache = new Dictionary<float, Dictionary<string, bool>>();

    public static bool CheckIsRecentCreate(string path, float time = 2678400)
    {
        var createTime = GetFirstUpdateTime(path);
        double nowTime = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
        return nowTime - createTime < time;
    }

    public static bool CheckIsRecentUpdate(string path, float time = 2678400, bool checkDirectory = true)
    {
        if (UpdateTimeLimit != -1)
        {
            time = UpdateTimeLimit;
        }
        bool isDirectory = false;
        FileInfo fileInfo = new FileInfo(path);
        if (!fileInfo.Exists)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);
            if (directoryInfo.Exists)
            {
                path = directoryInfo.FullName;
                isDirectory = true;
                if (DirUpdateTimeCache.ContainsKey(time) && DirUpdateTimeCache[time].ContainsKey(path))
                {
                    return DirUpdateTimeCache[time][path];
                }
            }
            else
            {
                //Debug.LogErrorFormat("路径错误：{0}", path);
            }
        }
        else
        {
            path = fileInfo.Name;
            if (checkDirectory)
            {
                bool directoryUpdate = CheckIsRecentUpdate(fileInfo.DirectoryName, time);
                if (!directoryUpdate)
                {
                    //Debug.Log("目录的记录都没更新文件肯定没更新 : "+path);
                    return false;
                }
            }
        }
        string log, err;
        ExecuteGitCommand(string.Format("log --pretty=format:\"%at\" -1 {0}", path), fileInfo.DirectoryName, out log, out err);
        string[] lines = log.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length > 0)
        {
            double commitTime = double.Parse(lines[0]);
            double nowTime = (DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
            bool result = nowTime - commitTime < time;
            if (isDirectory)
            {
                if (!DirUpdateTimeCache.ContainsKey(time))
                {
                    DirUpdateTimeCache.Add(time, new Dictionary<string, bool>());
                }
                DirUpdateTimeCache[time].Add(path, result);
            }
            return result;
        }
        return false;
    }

    public static double GetLastUpdateTime(string filePath)
    {
        FileInfo fileInfo = new FileInfo(filePath);
        string log, err;
        ExecuteGitCommand(string.Format("log --pretty=format:\"%at\" -1 {0} ", fileInfo.Name), fileInfo.DirectoryName, out log, out err);
        string[] lines = log.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length > 0)
        {
            double commitTime = double.Parse(lines[0]);
            return commitTime;
        }
        return 0;
    }

    public static double GetFirstUpdateTime(string path)
    {
        FileInfo fileInfo = new FileInfo(path);
        string log, err;
        string cmd = string.Format("log --pretty=format:\"%at\" --reverse --diff-filter=A \"{0}\"", fileInfo.Name);
        ExecuteGitCommand(cmd, fileInfo.DirectoryName, out log, out err, 1);
        string[] lines = log.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length > 0)
        {
            double commitTime = double.Parse(lines[0]);
            return commitTime;
        }
        return 0;
    }

    /// <summary>
    /// 是否在指定时间内有git操作
    /// </summary>
    public static bool CheckInTimeUpdate(string filePath, DateTime start, DateTime end)
    {
        FileInfo fileInfo = new FileInfo(filePath);
        if (!fileInfo.Exists)
        {
            ///Debug.LogErrorFormat("文件不存在：{0}", filePath);
            return false;
        }
        string log, err;
        ExecuteGitCommand(string.Format("log --pretty=format:\"%at\" -1 {0} ", fileInfo.Name), fileInfo.DirectoryName, out log, out err);
        string[] lines = log.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        if (lines == null || lines.Length == 0) return false;
        for (int i = 0; i < lines.Length; i++)
        {
            double commitTime = double.Parse(lines[i]);
            double endTime = (end - new DateTime(1970, 1, 1)).TotalSeconds;
            bool result = endTime - commitTime > 0 && endTime - commitTime < (end - start).TotalSeconds;
            return result;
        }
        return false;
    }

    // 检查文件是否已经在版本控制
    public static bool CheckFileTracked(string filePath)
    {
        FileInfo fi = new FileInfo(filePath);
        string cmd = string.Format("ls-files {0}", fi.Name);
        string log, errorLog;
        ExecuteGitCommand(cmd, fi.DirectoryName, out log, out errorLog);
        return log.Length > 0;
    }

    // 将某个文件还原修改
    public static void RevertFile(string filePath)
    {
        FileInfo fi = new FileInfo(filePath);
        string cmd = string.Format("checkout -- {0}", fi.Name);
        string log, errorLog;
        ExecuteGitCommand(cmd, fi.DirectoryName, out log, out errorLog);
        if (errorLog.Length > 0)
        {
            //Debug.LogError(errorLog);
        }
    }

    public static bool IsAssetsExistInMaster(string filePath)
    {
        string workDir = filePath;// (Application.dataPath + filePath).Replace("AssetsAssets", "Assets/");
        workDir = workDir.Substring(0, workDir.LastIndexOf('/'));
        string cmd = string.Format("cat-file -e master:UnityProj/{0}", filePath);
        try
        {
            string log, error;
            ExecuteGitCommand(cmd, workDir, out log, out error);
            return string.IsNullOrEmpty(log) && string.IsNullOrEmpty(error); //不存在时error不为空
        }
        catch (Exception e)
        {
            return false;
        }
    }

    public static void ExecuteGitCommand(string arguments, string workDirectory, out string output, out string error, int maxLogCount = 100)
    {
        var info = new ProcessStartInfo("git", arguments)
        {
            CreateNoWindow = true,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            WorkingDirectory = workDirectory
        };

        using (var process = new Process { StartInfo = info })
        {
            process.Start();
            int index = 0;
            StringBuilder sb = new StringBuilder();
            var streamReader = process.StandardOutput;
            while (!streamReader.EndOfStream && index < maxLogCount)
            {
                sb.AppendLine(streamReader.ReadLine());
                index++;
            }
            output = sb.ToString();
            var errorStream = process.StandardError;
            error = errorStream.ReadToEnd();
            process.Close();
        }
    }


}
